#include <gflags/gflags.h>
#include <brpc/server.h>
#include <butil/logging.h>
#include <brpc/stream.h>
#include "/home/pigff/project/search_engine/search_engine.h"
#include "SG.pb.h"

DEFINE_bool(attachment, true, "Echo attachment as well");      
DEFINE_int32(port, 9999, "TCP Port of this server");
DEFINE_int32(idle_timeout_s, -1, "Connection will be closed if there is no "
                          "read/write operations during the last `idle_timeout_s'");
DEFINE_int32(logoff_ms, 2000, "Maximum duration of server's LOGOFF state "
                          "(waiting for client to close connection before server stops)");

namespace Search{
//实现proto中的Service基类
class SearchService : public SG::Service{
public:
    SearchService(){
        //在构造函数中调用Load加载好索引文件
        Load(inverted_index,forward_index);   
    }

    void Search(google::protobuf::RpcController* cntl_base,
                const SG::Request* req,
                SG::Response* resp,
                google::protobuf::Closure* done){
        //这个对象确保在return时自动调用done->Run()
        brpc::ClosureGuard done_guard(done);

        brpc::Controller* cntl = static_cast<brpc::Controller*>(cntl_base);
        
        //输出日志了解客户端如何与服务器交互
        LOG(INFO) << "Received request[log_id=" << cntl->log_id() 
            << "] from " << cntl->remote_side() 
            << " to " << cntl->local_side()
            << ": " << req->keyword()
            << " (attached=" << cntl->request_attachment() << ")";

        //在倒排哈希表中根据关键词分词查找
        std::unordered_map<string,int> ids;
        // 如果找不到则响应的几个参数都不设置，都为空
        if(Find(inverted_index,req->keyword(),ids) == false)
             return;

        //对搜索出的结果进行关联度排序
        vector<std::pair<string,int> > sort_ids = Sort(ids);
           
        //取出排序好的id的相关内容
        vector<News_Info> infos = ReturnInfo(sort_ids,forward_index); 

        for(size_t i = 0;i < infos.size();++i)
            resp->add_info();
        //给响应写东西
        for(int i = 0;i < resp->info_size();++i){
            SG::Info* info = resp->mutable_info(i);
            info->set_title(infos[i].title);
            info->set_author(infos[i].author);
            info->set_date(infos[i].date);
        }

        if(FLAGS_attachment){
            //设置连接到网络的附件而不是被序列化的protobuf信息
            cntl->response_attachment().append(cntl->request_attachment()); 
        }
    }    
private:
    std::unordered_map<string,std::unordered_set<string>> inverted_index;
    std::unordered_map<string,std::unordered_map<string,string>> forward_index;
};

}//end namespace

int main(int argc,char* argv[]){
    daemon(1,1);
    //解析GFLAGS
    gflags::ParseCommandLineFlags(&argc,&argv,true);
    
    //服务器对象
    brpc::Server server;
    
    //proto服务的实例
    Search::SearchService search_service;

    //将服务添加到服务器中
    //第二个参数是因为服务放在堆栈上，我们不希望服务器删除它
    //如果想要删除可以用brpc::SERVER_OWNS_SERVICE
    if(server.AddService(&search_service,brpc::SERVER_DOESNT_OWN_SERVICE) != 0){
        LOG(ERROR) << "Fail to start SearchServer";
        return -1;
    }

    // Start the server.
    brpc::ServerOptions option;
    option.idle_timeout_sec = FLAGS_idle_timeout_s;
    if (server.Start(FLAGS_port, &option) != 0) {
        LOG(ERROR) << "Fail to start EchoServer";
        return -1;
    }
    //直到按下Ctrl-c，才停止服务器
    server.RunUntilAskedToQuit();
    return 0;
}
